﻿using System.ComponentModel;
using AnalyStock.DataManage;
using MathNet.Numerics;

namespace AnalyStock.WPFPage;

public partial class LoadDataPage
{
    private IList<Daily> dailies_One, dailies_Two;
    private DownloadProgress downloadProgress;
    private int idxCalendars; //日历索引，为根据日历循环下载数据计数 

    //导入期间数据数据根据股票代码
    private IList<string> stockCodes_One, stockCodes_Two;

    //导入单日交易数据根据交易日历
    private IList<TradeCalendar> tradeCalendars; //保存日历集合

    private void BtnCancelProgress_Click(object sender, RoutedEventArgs e)
    {
        downloadProgress?.Cancel();
    }

    private void IniDownloadProgress()
    {
        DisposeProgress();
        downloadProgress = new DownloadProgress();
        downloadProgress.ProgressChanged += (s, e) =>
        {
            if (e.TaskNo is "No1")
            {
                barProgress1.Value = e.ProgressPercentage;
                textProgress1.Text = e.UserState;
            }
            else
            {
                barProgress2.Value = e.ProgressPercentage;
                textProgress2.Text = e.UserState;
            }
        };
    }

    private void DisposeProgress()
    {
        if (downloadProgress is not null)
        {
            downloadProgress.Dispose();
            downloadProgress = null;
        }
    }

    /// <summary>
    ///     双任务下载入口
    /// </summary>
    /// <returns></returns>
    private async Task DownloadByMultiTaskAsync()
    {
        if (IsWrongOfCheckFormatting("DownAllStockOnPeriod") ||
            !"批量追加信息需要较长时间,是否确认?".IsConfirmMessage())
        {
            return;
        }

        InitializeWork();
        try
        {
            switch (downDataType)
            {
                case DownloadDataType.TradeOnDaily:
                    if (await IsGetTradeCalendarAsync() && await IsGetDailyOnLoopAsync())
                    {
                        await DoworkOnDailyAsync(downloadProgress);
                    }

                    break;
                case DownloadDataType.TradeOnPeriod:
                    if (await IsGetStockCodeAsync())
                    {
                        await DoworkOnPeriodAsync<Daily>(downloadProgress);
                    }

                    break;
                case DownloadDataType.FinanceOnPeriod:
                    if (await IsGetStockCodeAsync())
                    {
                        await DoworkOnPeriodAsync<DynamicFinancialIndex>(downloadProgress);
                    }

                    break;
            }
        }
        catch (Exception ex)
        {
            downloadProgress.Cancel();
            ex.Message.ErrorMessage();
        }
        finally
        {
            await DownFailLogOnLoopAsync();
        }
    }

    private enum DowningError
    {
        CalendarError,
        AllDowningErrorOnDay,
        SingleStockDowningError,
        StockCodeError
    }

    /// <summary>
    ///     获取下载数据
    /// </summary>
    /// <returns></returns>

    #region

    //获取交易日历
    private async ValueTask<bool> IsGetTradeCalendarAsync()
    {
        var (IsSuccees, IList) = await CommDataMethod<TradeCalendar>
            .IsGetDataOnlineAsync(DowningError.CalendarError.ToString(),
                startDate,
                endDate);
        tradeCalendars?.Clear();
        if (IsSuccees)
        {
            tradeCalendars = IList;
        }

        return IsSuccees;
    }

    //循环获取每日的全部股票交易数据
    private async ValueTask<bool> IsGetDailyOnLoopAsync()
    {
        bool IsLoadSuccees;
        IList<Daily> IList;
        do
        {
            if (idxCalendars >= tradeCalendars.Count)
            {
                return false;
            }

            (IsLoadSuccees, IList) = await CommDataMethod<Daily>.IsGetDataOnlineAsync(
                DowningError.AllDowningErrorOnDay.ToString(),
                tradeCalendars[idxCalendars].Cal_date);
            idxCalendars++;
        } while (!IsLoadSuccees);

        //数据下载成功
        dailies_One?.Clear();
        dailies_Two?.Clear();
        if (checkBoxMutilTask.IsChecked.Value) //是否双任务
        {
            var countInSection = IList.Count / 2;
            dailies_One = IList.Take(countInSection).ToList();
            dailies_Two = IList.Skip(countInSection).ToList();
        }
        else
        {
            dailies_One = IList;
        }

        return true;
    }

    //获取股票代码
    private async ValueTask<bool> IsGetStockCodeAsync()
    {
        var (IsSuccees, IListData) = await CommDataMethod<StockBasic>
            .IsGetDataOnlineAsync(DowningError.StockCodeError.ToString());
        stockCodes_One?.Clear();
        stockCodes_Two?.Clear();
        if (IsSuccees)
        {
            var stockCodes = IListData.Select(n => n.Ts_code);
            if (checkBoxMutilTask.IsChecked.Value) //是否双任务
            {
                var countInDoubleSection = stockCodes.Count() / 2;
                stockCodes_One = stockCodes.Take(countInDoubleSection).ToList();
                stockCodes_Two = stockCodes.Skip(countInDoubleSection).ToList();
            }
            else //单后台任务执行
            {
                stockCodes_One = stockCodes.ToList();
            }
        }

        IListData.Dispose();
        return IsSuccees;
    }

    #endregion

    /// <summary>
    ///     补充下载失败记录
    /// </summary>

    #region

    private async Task DownFailLogOnLoopAsync()
    {
    LoopWorking:
        //如果过放弃下载执行,错误记录为零,放弃补充下载，则退出
        if (downloadProgress.IsCancel)
        {
            goto QuitWorking;
        }

        if (ErrorLogPool.ErrorLogs.Count == 0)
        {
            goto QuitWorking;
        }

        if (!$"{ErrorLogPool.ErrorLogs.Count}个失败记录，是否补充导入?".IsConfirmMessage())
        {
            goto QuitWorking;
        }

        //初始化工作过程...
        IniDownloadProgress();
        //清理相关数据变量
        ClearDataOnWorking();
        //整理失败记录,分类下载
        RepartErrorLogs();
        //处理根据交易日历导入的失败记录
        if (tradeCalendars.Count > 0)
        {
            //不是当日全部交易数据下载错误，则转到个股下载错误处理流程
            if (await IsGetDailyOnLoopAsync())
            {
                await DoworkOnDailyAsync(downloadProgress);
            }
        }

        //处理根据股票编码导入历史数据的失败记录
        if (stockCodes_One.Count > 0)
        {
            if (downDataType is DownloadDataType.FinanceOnPeriod)
            {
                await DoworkOnPeriodAsync<DynamicFinancialIndex>(downloadProgress);
            }
            else
            {
                await DoworkOnPeriodAsync<Daily>(downloadProgress);
            }
        }

        goto LoopWorking; //循环处理错误记录                                    
    QuitWorking:
        QuitDowork();
    }

    private void RepartErrorLogs()
    {
        //获取下载错误日的交易日历
        tradeCalendars = ErrorLogPool.ErrorLogs
            .Where(n => n.ProcessName.Equals(DowningError.AllDowningErrorOnDay.ToString()))
            .Select(n => new TradeCalendar { Cal_date = n.StockTradeDate }).ToList();
        //获取个股下载错误的记录
        stockCodes_One = ErrorLogPool.ErrorLogs
            .Where(n => n.ProcessName.Equals(DowningError.SingleStockDowningError.ToString()))
            .Select(n => n.StockCode).ToList();
        ErrorLogPool.ErrorLogs?.Clear();
    }

    //初始化相关记录
    private void InitializeWork()
    {
        btnLoadAllData.IsEnabled = false;
        btnStop.IsEnabled = true;
        ErrorLogPool.ErrorLogs ??= new List<ErrorLog>();
        ErrorLogPool.ErrorLogs.Clear();
        textProgress1.Text = "开始下载数据...";
        IniDownloadProgress();
        ClearDataOnWorking();
    }

    private void QuitDowork()
    {
        btnLoadAllData.IsEnabled = true;
        btnStop.IsEnabled = false;
        textProgress1.Text =
            downloadProgress.IsCancel ? "数据下载终止..." : "数据下载任务结束...";
        DisposeProgress();
        ClearDataOnWorking();
    }

    private void ClearDataOnWorking()
    {
        idxCalendars = 0;
        tradeCalendars.Dispose();
        stockCodes_One.Dispose();
        stockCodes_Two.Dispose();
        dailies_One.Dispose();
        dailies_Two.Dispose();
        textProgress2.Text = "";
        barProgress1.Value = 0;
        barProgress2.Value = 0;

    }

    #endregion

    /// <summary>
    ///     下载每日全部股票的交易数据
    /// </summary>
    /// <param name="progress"></param>
    /// <returns></returns>

    #region

    private async Task DoworkOnDailyAsync(IDownloadProgress progress)
    {
        if (progress.IsBusy)
        {
            return;
        }

        List<Task> downDatatoDbSetTasks = new(2);
        if (dailies_One.Any())
        {
            downDatatoDbSetTasks.Add(
                DownDatasToDbSetOnDailyAsync(progress,
                    "No1",
                    dailies_One,
                    progress.Token));
        }

        if (dailies_Two.Any())
        {
            downDatatoDbSetTasks.Add(
                DownDatasToDbSetOnDailyAsync(progress,
                    "No2",
                    dailies_Two,
                    progress.Token));
        }

        await Task.WhenAll(downDatatoDbSetTasks);

        if (await IsGetDailyOnLoopAsync())
        {
            await DoworkOnDailyAsync(downloadProgress);
        }
    }

    private static async Task DownDatasToDbSetOnDailyAsync(IDownloadProgress progress,
                                                           string noTask,
                                                           IList<Daily> list,
                                                           CancellationToken token)
    {
        var trdateDate = list.First().Trade_date;
        await foreach (int index in SaveToDbSetAsyncEnumerable().ConfigureAwait(false))
        {
            ChangeProgress(index);
            //await ChangeProgressVal(index).ConfigureAwait(false);
            if (token.IsCancellationRequested)
            {
                CancelProgress(index);
                throw new TaskCanceledException();
            }
        }
        return;

        async IAsyncEnumerable<int> SaveToDbSetAsyncEnumerable()
        {
            var index = 1;
            foreach (var item in list)
            {
                await SaveDataToDbSetOnSingleStockAsync(item).ConfigureAwait(false);
                yield return index++;
            }
        }

        //进度填写100，通知进度器，任务已经退出了。进度器将busys状态初始化为false
        void CancelProgress(int idx) => progress.Report(noTask, 100,
                                $"{trdateDate}日数据已下载第{idx}条记录,处理终止...");
        void ChangeProgress(int idx) =>
                progress.Report(noTask, idx * 100 / list.Count,
                                $"{trdateDate}日数据已下载第:{idx}条记录,共{list.Count}条记录");
    }

    private static async Task<int> SaveDataToDbSetOnSingleStockAsync(Daily item)
    {
        try
        {
            await Task.Delay(2);
            return await CommDataHelper<Daily>.SaveDataToDbSetAsync(new List<Daily> { item }, item.Ts_code)
                                              .ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            ErrorLogPool.LogErrorMessage(
                DowningError.SingleStockDowningError.ToString(),
                item.Ts_code,
                item.Trade_date,
                ex.Message);
            return -1;
        }
    }

    #endregion

    /// <summary>
    ///     批量导入：根据股票代码保存每只股票历史数据或财务数据
    /// </summary>

    #region
    private bool isWaitOn1minOnDowning = false; //针对tushare端口每分钟调用次数限制的下载数据
    private async Task DoworkOnPeriodAsync<T>(IDownloadProgress progress) where T : class, new()
    {
        if (progress.IsBusy)
        {
            return;
        }

        List<Task> downDatatoSaveDbSetTasks = new(2);
        if (stockCodes_One.Any())
        {
            downDatatoSaveDbSetTasks.Add(
                DownDatasToDbSetOnPeriodAsync<T>(progress,
                    "No1",
                    stockCodes_One,
                    startDate,
                    endDate,
                    progress.Token));
        }

        if (stockCodes_Two.Any())
        {
            downDatatoSaveDbSetTasks.Add(
                DownDatasToDbSetOnPeriodAsync<T>(progress,
                    "No2",
                    stockCodes_Two,
                    startDate,
                    endDate,
                    progress.Token));
        }

        await Task.WhenAll(downDatatoSaveDbSetTasks);
    }

    private async Task DownDatasToDbSetOnPeriodAsync<T>(IDownloadProgress progress,
        string noTask,
        IList<string> list,
        string startDate,
        string endDate,
        CancellationToken token) where T : class, new()
    {
        await foreach (int index in DownToDbSetAsyncEnumerable().ConfigureAwait(false))
        {
            //没下载95个记录就设置1分钟延时下载 
            if (index % 95 == 0 && isWaitOn1minOnDowning)
            {
                await DelayWaitfor65mAsync();
            }
            ChangeProgress(index);
            if (token.IsCancellationRequested)
            {
                CancelProgress();
                throw new TaskCanceledException();
            }
        }
        return;

        async IAsyncEnumerable<int> DownToDbSetAsyncEnumerable()
        {
            var index = 1;
            foreach (var code in list)
            {
                await DownDataToDbSetOnSingleStockAsync<T>(code, startDate, endDate).ConfigureAwait(false);
                yield return index++;
            }
        }

        async Task DelayWaitfor65mAsync()
        {
            try
            {
                await Task.Delay(65000, token);
            }
            catch (Exception)
            {
                CancelProgress();
                throw new TaskCanceledException();
            }
        }

        //进度填写100，通知进度器，任务已经退出了。进度器将busys状态初始化为false
        void CancelProgress() => progress.Report(noTask, 100, $"后台进程放弃处理,异常终止...");
        void ChangeProgress(int idx) =>
                progress.Report(noTask, idx * 100 / list.Count,
                $"{startDate[4..]}..{endDate[4..]}后台进程已处理第:{idx}条记录,共{list.Count}条记录");
    }

    private async Task<int>
    DownDataToDbSetOnSingleStockAsync<T>(string stockCode,
        string startDate,
        string endDate) where T : class, new()
    {
        try
        {
            var result =
                await CommDataHelper<T>.GetDataOnlineAsync(stockCode,
                    startDate,
                    endDate).ConfigureAwait(false);
            return
                await CommDataHelper<T>.SaveDataToDbSetAsync(result,
                    stockCode).ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            ErrorLogPool.LogErrorMessage(
                DowningError.SingleStockDowningError.ToString(),
                stockCode,
                endDate,
                ex.Message);
            return -1;
        }
    }

    #endregion
}